﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using libC.semantic;

namespace libC.translate
{
    //提示码
    internal enum ErrorCode
    {
        //返回值非法
        E_1001 = 1001,
        E_1002 = 1002,
        //参数非法
        E_2001 = 2001,
        E_2002 = 2002,
    }

    /// <summary>
    /// 翻译 工具类
    /// </summary>
    internal class transTool
    {
        /// <summary>
        /// 委托 参：semanticASTNode  返回：bool
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public delegate bool nodeRetBool(semanticASTNode node);

        /// <summary>
        /// 换行
        /// </summary>
        public const string LF = "\n";
        /// <summary>
        /// 空格
        /// </summary>
        public const string SP = " ";
        /// <summary>
        /// 空格4 （缩进）
        /// </summary>
        public const string SP4 = "    ";
        public const string RET_ARR_LEN = "__retArrLen_out";
        /// <summary>
        /// 命名空间
        /// </summary>
        public const string NSP = "namespace";
        


        public static readonly Dictionary<ErrorCode, string> TipMsgDic = new Dictionary<ErrorCode, string>()
        {
            [ErrorCode.E_1001] = "返回值非法：返回指针必须是 [空结构* , void* , char16_t*]其中的一种.",
            [ErrorCode.E_1002] = "返回值非法：指针别名必须 以_Array 结尾来表示数组.",
            [ErrorCode.E_2001] = "参数非法：指针参数必须是 [空结构* , void* , char16_t*]其中的一种，或者参数名以[_out , _arr , _handle]结尾.",
            [ErrorCode.E_2002] = $"参数非法：指针别名必须 必须有 (int* {RET_ARR_LEN}) 参数的定义.",
        };

        /// <summary>
        /// 添加 头部 信息字符串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="nodeTag"></param>
        public static void addHaedInfomation(ref string str , string nodeTag = "//")
        {
            string[] info = new string[] {
                "警告：这是自动生成的代码，不要手动去修改.",
                $"使用 wrapCLI 工具生成，工具版本为 <{libC.Version.ver}>.",
            };
            foreach (var item in info)
            {
                str += $"{nodeTag}{item}{LF}";
            }

            str += LF;
        }

        /// <summary>
        /// 获取 异常提示信息
        /// </summary>
        /// <param name="_c">异常类型</param>
        /// <returns></returns>
        public static string getErrorMsg(ErrorCode _c)
        {
            var _text = "";
            TipMsgDic.TryGetValue(_c, out _text);
            return $"errorCode {(int)_c} ,{_text}";
        }

        /// <summary>
        /// 获取类型的 基本名
        /// </summary>
        /// <param name="t_str">类型声明字符串</param>
        /// <returns></returns>
        public static string getTypeBaseName(string t_str)
        {
            var hasPoint = false;
            return getTypeBaseName(t_str, ref hasPoint);
        }

        /// <summary>
        /// 获取类型的 基本名
        /// </summary>
        /// <param name="t_str">类型声明字符串</param>
        /// <param name="hasPoint">是否有指针</param>
        /// <returns></returns>
        public static string getTypeBaseName(string t_str, ref bool hasPoint)
        {
            if (string.IsNullOrEmpty(t_str)) return "";
            //自定义类型名 放入 字典
            var cutIdx = t_str.IndexOf('*');

            if (cutIdx == -1)
            {
                //是否是 数组
                if (t_str[t_str.Length - 1] == ']')
                {
                    cutIdx = t_str.LastIndexOf('[');
                }
            }
            else
            {
                hasPoint = true;
            }

            if (cutIdx != -1)
            {
                t_str = t_str.Substring(0, cutIdx);

            }
            return t_str;
        }

        /// <summary>
        /// 筛选 有效函数（声明C动态导出的）
        /// </summary>
        /// <param name="funsDic">函数列表</param>
        /// <param name="ctypeDic">涉及类型列表(枚举、结构体、语言基础类型)</param>
        public static void limitFun(semanticAnalyzer _semAnaly, Dictionary<uint, List<uint>> funsDic, Dictionary<uint, List<uint>> ctypeDic)
        {
            var careTypeDic = new Dictionary<string, bool>();
            var ctypeSemDic = new Dictionary<uint, List<ISemanticInfo>>();
            var careCTypeSemDic = new Dictionary<string, ISemanticInfo>();
            var funSemList = new List<functionInfo>();
            var ctypeStructDic = new Dictionary<string, structInfo>();
            //遍历全部文件
            for (int i = 0, len = _semAnaly.astCount; i < len; i++)
            {
                uint astId = (uint)i;
                //单个文件
                var semAst = _semAnaly.getSemantAst(astId);
                var node = semAst.node;
                var ctypes = new List<uint>();
                var funs = new List<uint>();
                var ctypeSems = new List<ISemanticInfo>();
                //搜索有效 的函数
                traversesTree(node, (semanticASTNode n) =>
                {
                    var info = semAst.getSemantInfo(n.id);
                    if (info == null) return true;   //下一步
                    switch (info.getType())
                    {
                        //case SemanticInfoType.EXPR:
                        //    break;
                        //case SemanticInfoType.Field:
                        //    break;
                        case SemanticInfoType.FUNCTION:
                            //函数 
                            var funInfo = (functionInfo)info;
                            //是否是指针函数定义
                            if (funInfo.isPoint)
                            {
                                ctypeSems.Add(funInfo);
                                ctypes.Add(n.id);
                                funSemList.Add(funInfo);
                                return true;
                            }
                            //判读是否是 动态库导出函数
                            if (funInfo.firstID == null || !_semAnaly.defExternCDic.ContainsKey(funInfo.firstID)) return true;
                            funs.Add(n.id);
                            careTypeDic[getTypeBaseName(funInfo.ret_type)] = true;
                            funSemList.Add(funInfo);
                            //遍历参数 语义信息
                            var argLen = funInfo.args.Count;
                            if (argLen < 1) return true;
                            for (int i = 0; i < argLen; i += 2)
                            {
                                var f_t = funInfo.args[i];
                                var f_name = funInfo.args[i + 1];
                                if (string.IsNullOrEmpty(f_t)) continue;
                                //自定义类型名 放入 字典
                                f_t = getTypeBaseName(f_t);
                                careTypeDic[f_t] = true;
                            }

                            break;
                        case SemanticInfoType.ENUM:
                            //枚举
                            var enumInfo = (enumInfo)info;
                            var e_isInside = enumInfo.scopeArr.Count > 0;
                            if (e_isInside) break;   //内部 枚举不收集

                            //if (!semAst.customTypeDic.ContainsKey(enumInfo.name)) return true;
                            ctypeSems.Add(enumInfo);
                            ctypes.Add(n.id);
                            break;
                        case SemanticInfoType.STRUCT:
                            var structInfo = (structInfo)info;
                            var s_isInside = structInfo.scopeArr.Count > 0;
                            if (!s_isInside)
                            {
                                ctypeSems.Add(structInfo);
                                ctypes.Add(n.id);
                            }
                            var s_name = getFillScopeN(structInfo.scopeArr) + structInfo.name;
                            //放入 字典
                            if (!ctypeStructDic.ContainsKey(s_name))
                            {
                                ctypeStructDic[s_name] = structInfo;
                            }
                            else
                            {
                                var sameNS = ctypeStructDic[s_name];
                                //有重名 结构体
                                if (sameNS.decls.Count < 1)
                                {
                                    //它只是 声明 ，覆盖
                                    ctypeStructDic[s_name] = structInfo;
                                }
                            }
                            //return false;   //中断结构体向子节点的遍历
                            break;
                        case SemanticInfoType.TYPE_ALIAS:
                            var taInfo = (typeAliasInfo)info;
                            ctypeSems.Add(taInfo);
                            ctypes.Add(n.id);
                            break;
                    }

                    return true;
                });

                if (funs.Count > 0) funsDic.Add(astId, funs);
                if (ctypes.Count > 0) ctypeDic.Add(astId, ctypes);
                if (ctypeSems.Count > 0) ctypeSemDic.Add(astId, ctypeSems);
            }

            //ctypeDic 先检查结构体，把结构体中类型字段也放入ctypeDic
            foreach (var item in ctypeStructDic)
            {
                var _name = item.Key;
                var _SInfo = item.Value;
                //检查结构体 是否 需要
                var isInCare = false;
                var _tName = _name;
                if (_SInfo.scopeArr.Count > 0)
                {
                    _tName = _SInfo.scopeArr[0];
                }
                careTypeDic.TryGetValue(_tName, out isInCare);
                if (!isInCare) continue;
                //检查结构体 字段的类型，是自定义类型 放入 careTypeDic
                ckStructField2Care(_SInfo, ctypeStructDic, careTypeDic);
            }

            //ctypeDic 剔除没有函数参数声明的类型
            var helpList = new List<uint>();
            foreach (var itemDic in ctypeSemDic)
            {
                helpList.Clear();
                var _astID = itemDic.Key;
                var _listSem = itemDic.Value;
                if (!ctypeDic.ContainsKey(_astID)) continue;
                var _listT = ctypeDic[_astID];
                for (int i = 0, len = _listSem.Count; i < len; i++)
                {
                    var sem = _listSem[i];
                    var _tName = sem.name;
                    if (string.IsNullOrEmpty(_tName)) continue;
                    //是否在 函数参数声明、结构体声明 类型字典中？
                    if (!careTypeDic.ContainsKey(_tName)) continue;
                    var _nId = _listT[i];
                    helpList.Add(_nId);
                    if (!careCTypeSemDic.ContainsKey(_tName))
                    {
                        careCTypeSemDic[_tName] = sem;
                    }
                    else
                    {
                        Console.WriteLine($"检测到 {_tName}，类型 {Enum.GetName(typeof(SemanticInfoType), sem.getType())} 有重复声明.");
                    }
                }

                if (helpList.Count < 1)
                {
                    ctypeDic.Remove(_astID);
                    continue;
                }
                //替换 筛选后的数据 
                _listT.Clear();
                _listT.AddRange(helpList);
            }

            //分析 函数 定义是否遵照约定
            foreach (var item in funSemList)
            {
                if (!string.IsNullOrEmpty(item.exception)) continue;    //已经检查过了
                ckFunConvention(item, careCTypeSemDic);
            }

            //end
            helpList.Clear();
            careTypeDic.Clear();
            ctypeSemDic.Clear();
            careCTypeSemDic.Clear();
            funSemList.Clear();
        }

        /// <summary>
        /// 遍历 树
        /// </summary>
        /// <param name="_node">节点</param>
        /// <param name="act">遍历执行函数 ， 返回 false 中断向下子节点的遍历</param>
        //public static void traversesTree(semanticASTNode _node, Action<semanticASTNode> act)
        public static void traversesTree(semanticASTNode _node, nodeRetBool act)
        {
            if (_node == null) return;
            var r = act.Invoke(_node);
            if (!r) return; // 返回 false 中断向下子节点的遍历
            if (_node.children == null) return;
            for (int i = 0, len = _node.children.Count; i < len; i++)
            {
                var c = _node.children[i];
                traversesTree(c, act);
            }
        }

        /// <summary>
        /// 缩进，根据 等级
        /// </summary>
        public static string indentSp(int _indentLevel)
        {
            string result = "";
            for (int i = 0; i < _indentLevel; i++)
                result += SP4;
            return result;
        }

        //检查函数的约定规则
        private static void ckFunConvention(functionInfo _info, Dictionary<string, ISemanticInfo> cTypeSemDic)
        {
            //var _info = (functionInfo)semAst.getSemantInfo(funInfoId);
            //检查返回值
            var hasPoint = false;
            var _n = getTypeBaseName(_info.ret_type, ref hasPoint);
            //检查 返回值类型 是否 不合约定
            if (hasPoint)
            {
                //排除 void* 、char16_t* 
                if (_n != "void" && _n != "char16_t")   //字典优化
                {
                    //排除 空结构*
                    var isVoidStrcut = false;
                    if (cTypeSemDic.ContainsKey(_n))
                    {
                        var t_info = cTypeSemDic[_n];
                        if (t_info.getType() == SemanticInfoType.STRUCT)
                        {
                            var s_info = (structInfo)t_info;
                            isVoidStrcut = s_info.decls.Count < 1;
                        }
                    }
                    if (!isVoidStrcut)
                    {
                        //检测到非法， 添加 异常信息
                        var expStr = $"{_info.name} -> {_info.ret_type} {getErrorMsg(ErrorCode.E_1001)}\n";
                        _info.exception += expStr;
                        printTextColor(expStr, ConsoleColor.Yellow);
                    }
                }
            }
            else
            {
                ISemanticInfo retTSem;
                cTypeSemDic.TryGetValue(_n, out retTSem);
                typeAliasInfo taSem = null;
                if (retTSem != null && retTSem.getType() == SemanticInfoType.TYPE_ALIAS)
                {
                    taSem = (typeAliasInfo)retTSem;
                }
                //检查 是否是类型指针 别名
                if (taSem != null && taSem.isPoint)
                {
                    //是 ，检查是否 _Array 结尾
                    var isAssry = _n.Length > 6 && _n.Substring(_n.Length - 6) == "_Array";
                    if (!isAssry)
                    {
                        //检测到非法， 添加 异常信息，‘指针别名 必须 以_Array 结尾来表示，数组。’
                        var expStr = $"{_info.name} -> {_info.ret_type} {getErrorMsg(ErrorCode.E_1002)}\n";
                        _info.exception += expStr;
                        printTextColor(expStr, ConsoleColor.Yellow);
                    }
                    else
                    {
                        //检查参数列表中，是否有 返回数组长度定义（  int * __retArrLen_out 的定义）
                        var _args = _info.args;
                        bool hasReArrLenDecl = false;
                        for (int i = 0, len = _args.Count; i < len; i+=2)
                        {
                            var t_t = _args[i];
                            var t_n = _args[i + 1];
                            if (t_t == "int*" && t_n == RET_ARR_LEN) {
                                hasReArrLenDecl = true;
                                break;
                            }
                        }

                        if (!hasReArrLenDecl) {
                            var expStr = $"{_info.name} -> {_info.ret_type} {getErrorMsg(ErrorCode.E_2002)}\n";
                            _info.exception += expStr;
                            printTextColor(expStr, ConsoleColor.Yellow);
                        }
                    }
                }
            }

            //检查参数列表 是否 不合约定
            var args = _info.args;
            for (int i = 0, len = args.Count; i < len; i += 2)
            {
                var _t = _info.args[i];
                var _aN = _info.args[i + 1];
                var t_hp = false;
                var t_n = getTypeBaseName(_t, ref t_hp);
                //
                structInfo a_s_info = null;
                functionInfo a_f_info = null;
                ISemanticInfo a_semInfo = null;
                cTypeSemDic.TryGetValue(t_n, out a_semInfo);
                if (a_semInfo != null)
                {
                    switch (a_semInfo.getType())
                    {
                        case SemanticInfoType.STRUCT: a_s_info = a_semInfo as structInfo; break;
                        case SemanticInfoType.FUNCTION: a_f_info = a_semInfo as functionInfo; break;
                    }
                }

                if (!t_hp)
                {
                    //不是指针
                    if (a_f_info != null)
                    {
                        ////如果 是 函数指针类型，走函数检测递归
                        ////通过 函数指针类型 
                        //var fpID = 0u;
                        //ckFunConvention(semAst, fpID, cTypeSemDic);
                    }
                    continue;
                }
                //检查* 的相关约定
                //排除 char16_t* 、void*
                if (t_n == "char16_t" || t_n == "void") continue;
                //排除 空结构*   
                if (a_s_info != null && a_s_info.decls.Count < 1) continue;

                //排除 _out _handle _arr
                var _idx = _aN.LastIndexOf("_");
                if (_idx != -1)
                {
                    var suffix = _aN.Substring(_idx);
                    if (suffix == "_out" || suffix == "_handle" || suffix == "_arr") continue;  //用字典优化
                }
                //检测到非法， 添加 异常信息，‘参数’
                var expStr = $"{_info.name} ({_t} {_aN}) {getErrorMsg(ErrorCode.E_2001)}\n";
                _info.exception += expStr;
                printTextColor(expStr, ConsoleColor.Yellow);
            }
        }

        /// <summary>
        /// 打印颜色log
        /// </summary>
        /// <param name="text">信息</param>
        /// <param name="_c">颜色</param>
        public static void printTextColor(string text, ConsoleColor _c = ConsoleColor.White)
        {
            Console.ForegroundColor = _c;
            Console.WriteLine(text);
            Console.ResetColor();
        }

        /// <summary>
        /// 获取函数的 异常信息
        /// </summary>
        /// <param name="_fun">函数信息</param>
        /// <param name="funPointDic">函数指针字典</param>
        /// <returns></returns>
        public static string getFunExcep(functionInfo _fun, Dictionary<string, functionInfo> funPointDic)
        {
            string result = "";
            //参数 函数指针检查
            for (int i = 0, len = _fun.args.Count; i < len; i += 2)
            {
                var _t = _fun.args[i];
                if (_t == null) continue;
                functionInfo funP;
                funPointDic.TryGetValue(_t, out funP);
                if (funP != null)
                {
                    result += funP.exception;
                }
            }
            result += _fun.exception;
            return result;
        }

        /// <summary>
        /// 完整域名
        /// </summary>
        /// <param name="scopeArr">域字符串列表</param>
        /// <param name="connectStr">连接符号</param>
        /// <returns></returns>
        public static string getFillScopeN(List<string> scopeArr, string connectStr = ".")
        {
            if (scopeArr == null || scopeArr.Count < 1) return "";
            string result = "";
            foreach (var item in scopeArr)
                result += $"{item}{connectStr}";
            return result;
        }

        //检查记录 结构体字段的自定义类型 
        private static void ckStructField2Care(structInfo info, Dictionary<string, structInfo> _sDic, Dictionary<string, bool> recordDic)
        {
            var decls = info.decls;
            //遍历 字段
            for (int i = 0, len = decls.Count; i < len; i += 2)
            {
                var _t = decls[i];
                var _n = decls[i + 1];
                //类型
                var b_t = getTypeBaseName(_t);
                if (!string.IsNullOrEmpty(b_t))
                {
                    recordDic[b_t] = true;
                }
                if (_sDic.ContainsKey(b_t))
                {
                    //该类型是一个结构，递归处理。  
                    ckStructField2Care(_sDic[b_t], _sDic, recordDic);
                }
            }

            //结构体内部结构定义处理

        }
    }
}
